package com.jdd.modules.sdkidentifyresultpushlog.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.jdd.common.api.vo.Result;
import com.jdd.common.api.vo.ResultVo;
import com.jdd.common.aspect.annotation.AutoLog;
import com.jdd.common.constant.CacheConstant;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.constant.LedConstant;
import com.jdd.common.system.query.QueryGenerator;
import com.jdd.common.util.*;
import com.jdd.common.util.excel.entity.params.ExportParams;
import com.jdd.common.util.excel.entity.params.ImportParams;
import com.jdd.common.util.excel.util.ExcelImportUtil;
import com.jdd.common.util.excel.web.entity.vo.NormalExcelConstants;
import com.jdd.common.util.excel.web.view.EasypoiSingleExcelView;
import com.jdd.config.websocket.WebSocketServer;
import com.jdd.modules.configcartype.entity.ConfigCarType;
import com.jdd.modules.configcartype.service.IConfigCarTypeService;
import com.jdd.modules.operationLog.service.IParkHandOverLogService;
import com.jdd.modules.order.entity.ParkOrderInfo;
import com.jdd.modules.order.service.IParkOrderInfoService;
import com.jdd.modules.parkcar.entity.ParkCarMonthly;
import com.jdd.modules.parkcar.entity.ParkCarOutAbnormalLog;
import com.jdd.modules.parkcar.entity.ParkCarStored;
import com.jdd.modules.parkcar.mapper.ParkCarOutAbnormalLogMapper;
import com.jdd.modules.parkcar.mapper.ParkCarStoredMapper;
import com.jdd.modules.parkcar.service.IParkCarMonthlyService;
import com.jdd.modules.parking.entity.ConfigParkInfo;
import com.jdd.modules.parking.entity.ParkArmInfo;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.entity.ParkCarOutLog;
import com.jdd.modules.parking.mapper.ParkArmInfoMapper;
import com.jdd.modules.parking.mapper.ParkCarEnterLogMapper;
import com.jdd.modules.parking.service.*;
import com.jdd.modules.sdk.LedCallInterface;
import com.jdd.modules.sdk.SdkCallInterface;
import com.jdd.modules.sdk.config.CameraSdk;
import com.jdd.modules.sdkidentifyresultpushlog.entity.*;
import com.jdd.modules.sdkidentifyresultpushlog.mapper.SdkIdentifyResultPushLogMapper;
import com.jdd.modules.sdkidentifyresultpushlog.service.ChargeFeeService;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogService;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogV3Service;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import sun.misc.BASE64Encoder;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: sdk识别结果管理
 * @Author: jdd
 * @Date: 2021-03-31
 * @Version: V1.0
 */
@Slf4j
@Api(tags = "sdk识别结果管理")
@RestController
@RequestMapping("/sdkidentifyresultpushlog/sdkIdentifyResultPushLog")
public class SdkIdentifyResultPushLogController {
    @Resource
    private ISdkIdentifyResultPushLogService sdkIdentifyResultPushLogService;
    @Resource
    private ISdkIdentifyResultPushLogV3Service sdkIdentifyResultPushLogV3Service;
    @Resource
    private SdkIdentifyResultPushLogMapper sdkIdentifyResultPushLogMapper;
    @Resource
    private IParkArmInfoService parkArmInfoService;
    @Resource
    private ParkArmInfoMapper parkArmInfoMapper;
    @Resource
    private IParkCarMonthlyService parkCarMonthlyService;
    @Resource
    private IparkCarEnterLogService parkCarEnterLogService;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private SimilarityRatioAlgorithm similarityRatioAlgorithm;
    @Resource
    private IConfigCarTypeService carTypeService;
    @Resource
    private IParkOrderInfoService parkOrderInfoService;
    @Resource
    private ChargeFeeService chargeFeeService;
    @Resource
    private LedCallInterface ledCallInterface;
    @Resource
    private ParkCarOutAbnormalLogMapper parkCarOutAbnormalLogMapper;
    @Resource
    private ParkCarStoredMapper parkCarStoredMapper;
    @Resource
    private ParkCarEnterLogMapper parkCarEnterLogMapper;
    @Resource
    private IParkWorkStationService parkWorkStationService;
    @Resource
    private IParkHandOverLogService parkHandOverLogService;
    @Resource
    private RestTemplateUtils restTemplateUtils;
    @Resource
    private WebSocketServer socketServer;

    public String appScrect;

    public String appId;


    @Resource
    private IConfigParkInfoService configParkInfoService;
    @Resource
    private SdkCallInterface sdkCallInterface;
    @Value("${parkInfo.parkCode}")
    public String parkCode;
    @Resource
    private IparkCarOutLogService parkCarOutLogService;

    @Resource
    private CacheUtil cacheUtill;

    @Resource
    private CameraSdk cameraSdk;

    /**
     * 取最近入场的条数
     */
    public static final int INCOME_NUMBER_FIVE = 5;


    /**
     * 当没有车辆出厂记录时，通过车牌号模糊查询车辆入场记录
     *
     * @param plateNo
     * @return
     * @author koubolun
     */
    @AutoLog(value = "根据车牌模糊查询")
    @ApiOperation(value = "根据车牌模糊查询")
    @GetMapping(value = "/findLikePlateNo")
    public Result<List<ParkCarEnterLog>> findLikePlateNo(@RequestParam("plateNo") String plateNo) {
        Result<List<ParkCarEnterLog>> result = new Result<>();
        if (StringUtils.isEmpty(plateNo)) {
            return result.error500("车牌号不能为空");
        }
        //系统数据库不支持分组查多个列
        List<ParkCarEnterLog> enterLogList = this.sdkIdentifyResultPushLogMapper.getParkCarEnterLogLikePlateNo(plateNo);
        //用流去重
        enterLogList = enterLogList.stream()
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ParkCarEnterLog::getPlateNo))), ArrayList::new));
//        List<ParkCarEnterLog> resultList = null;
        //只取最近入场的前5条数据
//        if (enterLogList.size() > JddConstant.IntNumber.INT_FIVE) {
//            resultList = enterLogList.subList(JddConstant.IntNumber.INT_ZERO, JddConstant.IntNumber.INT_FIVE);
//        } else {
//            resultList = enterLogList;
//        }
        result.setSuccess(true);
        result.setResult(enterLogList);
        return result;

    }


    @AutoLog(value = "确认开闸 允许 保存入场记录")
    @ApiOperation(value = "确认开闸 允许 保存入场记录")
    @PostMapping(value = "/openedSaveParkCarEnterLog")
    public Result<?> openedSaveParkCarEnterLog(@RequestBody ReChargeVo reChargeVo) {
        try {
            reChargeVo.setEnterDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            //查询出口车道的信息
            ParkArmInfo parkArmInfo = parkArmInfoMapper.getParkArmBySerialNo(reChargeVo.getSerialNo());
            if (null == parkArmInfo) {
                return Result.error("查不到车场信息");
            }
            QueryWrapper<SdkIdentifyResultPushLog> wrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(reChargeVo.getSerialNo())) {
                wrapper.eq("serial_no", reChargeVo.getSerialNo());
            }
            wrapper.eq("license", reChargeVo.getPlateNo());
            wrapper.orderByDesc("create_time");
            wrapper.last("limit 1");
            List<SdkIdentifyResultPushLog> list = sdkIdentifyResultPushLogService.list(wrapper);
            SdkIdentifyResultPushLog sdkIdentifyResultPushLog = CollectionUtil.isEmpty(list) ? null : list.get(0);

            ParkCarEnterLog parkCarEnterLog = parkArmInfoService.getParkCarEnterLog(parkArmInfo, reChargeVo, sdkIdentifyResultPushLog);
            //加上工作站名和岗亭人账户
            String workUser = parkWorkStationService.getStationOperationNameByParkArm(parkArmInfo);
            if (ObjectUtil.isNotEmpty(workUser)) {
                parkCarEnterLog.setWorkName(parkArmInfo.getWorkStationName());
                parkCarEnterLog.setSysUserName(workUser);
            }
            //保存入场记录
            parkCarEnterLogService.save(parkCarEnterLog);
            //允许入场 语音播报 并发送记录到云端
            sdkIdentifyResultPushLogService.openedSaveParkCarEnterLog(reChargeVo, parkCarEnterLog);
            Map<String, Object> data = parkArmInfoService.getData(workUser);
            socketServer.sendMessageAll(JSONObject.toJSONString(data));
            return Result.ok("入场成功！");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("入场异常！");
        }
    }


    @AutoLog(value = "确认开闸 拒绝 语音播报")
    @ApiOperation(value = "确认开闸 拒绝 语音播报")
    @PostMapping(value = "/refuseCarEnter")
    public Result<?> refuseCarEnter(@RequestBody ReChargeVo reChargeVo) {
        try {
            sdkIdentifyResultPushLogService.refuseCarEnter(reChargeVo);
            return Result.ok("操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("操作失败");
        }
    }

    /**
     * @author lcy
     * @date 2021/9/2
     * @Description 不模糊匹配，根据时间生成入场纪录后返回计费信息
     */
    @AutoLog(value = "补录生成入场纪录，后端重新计费，然后返回计费信息")
    @ApiOperation(value = "补录生成入场纪录，后端重新计费，然后返回计费信息")
    @PostMapping(value = "/againChargeSaveEnterForCurrentOutCar")
    public Result<ParkOrderInfoVO> againChargeSaveEnterForCurrentOutCar(@RequestBody ReChargeVo reChargeVo) {
        try {
            //查询出口车道的信息
            ParkArmInfo parkArmInfo = parkArmInfoMapper.getParkArmBySerialNo(reChargeVo.getSerialNo());
            if (null == parkArmInfo) {
                return Result.error("查不到车道信息");
            }
            //补录入场纪录并上传到云端
            //补的入场记录序列号是出场的
            ParkCarEnterLog carEnterLog = sdkIdentifyResultPushLogService.createAbnormalParkCarEnterLog(parkArmInfo, reChargeVo);
            if (null == carEnterLog) {
                return Result.error("未查询到识别信息！补录失败");
            }
            //返回计费信息
            Result<ParkOrderInfoVO> parkOrderInfoVOResult = sdkIdentifyResultPushLogService.getParkOrderInfoVOResult(reChargeVo);
            if (200 != parkOrderInfoVOResult.getCode()) {
                return Result.error("计费规则调用失败!");
            }
            ParkOrderInfoVO result = parkOrderInfoVOResult.getResult();
            //选择出口相机
            result.setIpAddr(parkArmInfo.getIpAddr());
            result.setSerialNo(parkArmInfo.getSerialNo());
            //要有个图片
            result.setOutImgPath(carEnterLog.getImgPath());
            result.setOssOutImgPath(carEnterLog.getOssImgPath());
            //如果是储值车，就直接扣费放行关弹窗
            if (isCarStored(reChargeVo, parkArmInfo, result, carEnterLog)) {
                //储值车匹配后处理
                return doParkCarStored(reChargeVo, carEnterLog, parkArmInfo, parkOrderInfoVOResult, result, JddConstant.AbnormalType.ADD_ENTER_HASFEE);
            } else {
                //非储值车补录直接添加一条异常,但是状态是未支付的，放行或者扫码变成已支付
                ParkCarOutAbnormalLog parkCarOutAbnormalLog = new ParkCarOutAbnormalLog();
                BeanUtils.copyProperties(carEnterLog, parkCarOutAbnormalLog);
                parkCarOutAbnormalLog.setCreateTime(new Date());
                parkCarOutAbnormalLog.setCarEnterId(carEnterLog.getId());
                parkCarOutAbnormalLog.setIpAddr(parkArmInfo.getIpAddr());
                parkCarOutAbnormalLog.setOrderId(result.getId());
                parkCarOutAbnormalLog.setPayStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_UNPAID);
                parkCarOutAbnormalLogMapper.insert(parkCarOutAbnormalLog);
                //补录后，播报钱数，扫码放行
                ledCallInterface.OutShowFeeAll(parkArmInfo.getSerialNo(), reChargeVo.getPlateNo(), result);
            }
            //如果出场是白名单，再次识别下就行不用处理
            parkOrderInfoVOResult.setResult(result);
            return parkOrderInfoVOResult;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("补录生成入场纪录异常！");
        }
    }

    /**
     * 功能描述: 补录与匹配判断是否储值，储值就直接缴费放行
     *
     * @param reChargeVo  前端发来的数据
     * @param parkArmInfo 相机信息
     * @param result      订单信息
     * @param carEnterLog 入场纪录
     * @Author: lcy
     * @Date: 2021/9/29
     */
    private boolean isCarStored(ReChargeVo reChargeVo, ParkArmInfo parkArmInfo, ParkOrderInfoVO result, ParkCarEnterLog carEnterLog) throws IOException {
        String plateNo = null == reChargeVo.getOutPlateNo() ? reChargeVo.getPlateNo() : reChargeVo.getOutPlateNo();
        //判断是否储值车
        ParkCarStored parkCarStored = parkCarStoredMapper.getEntranceStored(plateNo, "Y");
        if (null != parkCarStored) {
            //余额
            Integer payFee = parkCarStored.getPayFee();
            //本次金额
            Integer unpayFee = Integer.parseInt(result.getChargeUnpaid()) / 100;
            if (payFee >= unpayFee) {
                log.info("储值车:{},余额大于本次费用-----余额:{},本次费用:{}", plateNo, payFee, unpayFee);
                //支付费用-本次金额=剩余金额
                int remaining = payFee - unpayFee;
                log.info("储值车出场:{},支付后余额为:{}", plateNo, remaining);
                ledCallInterface.OutStoredPayFeeAll(reChargeVo.getSerialNo(), plateNo, unpayFee, remaining, result);

                //保存订单
                ParkOrderInfo orderInfo = new ParkOrderInfo();
                orderInfo.setCarEnterId(result.getCarEnterId());
                orderInfo.setEnterTime(result.getEnterTime());
                orderInfo.setChargeTotalFee(result.getChargeUnpaid());
                orderInfo.setOutTime(DateUtils.formatDateTime());
                orderInfo.setId(SnowFlakeUtil.getId());
                orderInfo.setCreateTime(new Date());
                orderInfo.setParkCode(reChargeVo.getParkCode());
                orderInfo.setParkName(parkArmInfo.getParkName());
                orderInfo.setSerialNo(reChargeVo.getSerialNo());
                orderInfo.setPlateNo(plateNo);
                orderInfo.setPayTime(DateUtils.formatDateTime());
                orderInfo.setChargeDuration(result.getChargeDuration());
                orderInfo.setCarType("1");
                orderInfo.setChargeUnpaid(result.getChargeUnpaid());
                orderInfo.setChargeDue(result.getChargeUnpaid());
                orderInfo.setChargePaid(String.valueOf(result.getChargeUnpaid()));
                orderInfo.setOrderStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
                orderInfo.setPayType("5");
                //加上工作站名和岗亭人账户
                String workUser = parkWorkStationService.getStationOperationNameByParkArm(parkArmInfo);
                if (ObjectUtil.isNotEmpty(workUser)) {
                    orderInfo.setWorkName(parkArmInfo.getWorkStationName());
                    orderInfo.setSysUserName(workUser);
                }
                parkOrderInfoService.save(orderInfo);
                //出场记录
                ParkCarOutLog parkCarOutLog = new ParkCarOutLog();
                parkCarOutLog.setId(SnowFlakeUtil.getId());
                parkCarOutLog.setParkCode(parkArmInfo.getParkCode());
                parkCarOutLog.setParkName(parkArmInfo.getParkName());
                parkCarOutLog.setPlateNo(plateNo);
                parkCarOutLog.setCarEnterId(null != carEnterLog ? carEnterLog.getId() : null);
                parkCarOutLog.setSerialNo(reChargeVo.getSerialNo());
                parkCarOutLog.setCarNature(JddConstant.MqttRecResultPushLog.IS_WHITE_TWO);
                parkCarOutLog.setCarType(String.valueOf(JddConstant.IntNumber.INT_ONE));
                parkCarOutLog.setCarOutTime(DateUtil.getTime());
                parkCarOutLog.setArmName(parkArmInfo.getArmName());
                parkCarOutLog.setImgPath(carEnterLog.getImgPath());
                parkCarOutLog.setOssImgPath(carEnterLog.getOssImgPath());
                parkCarOutLog.setIpAddr(parkArmInfo.getIpAddr());
                parkCarOutLog.setCreateTime(new Date());
                parkCarOutLog.setSynchronousStatus(JddConstant.StatusType.STATUS_N);
                try {
                    //加上工作站名和岗亭人账户
                    if (ObjectUtil.isNotEmpty(workUser)) {
                        parkCarOutLog.setWorkName(parkArmInfo.getWorkStationName());
                        parkCarOutLog.setSysUserName(workUser);
                        parkHandOverLogService.updateHandOverAuto(parkCarOutLog, orderInfo, workUser, 1);
                    }
                } catch (Exception e) {
                    log.error("-----------------车辆出场交接班更新或者发送场内车辆详情失败----------------");
                }
                //更新储值车余额
                parkCarStored.setPayFee(remaining);
                parkCarStoredMapper.updateById(parkCarStored);
                return true;
            }
        }
        return false;
    }

    /**
     * @author lcy
     * @date 2021/9/2
     * @Description 模糊匹配后并重新计费
     */
    @AutoLog(value = "模糊匹配后，前端发送出口信息，后端重新计费，然后返回计费信息")
    @ApiOperation(value = "模糊匹配后，前端发送出口信息，后端重新计费，然后返回计费信息")
    @PostMapping(value = "/againChargeForCurrentOutCar")
    public Result<ParkOrderInfoVO> againChargeForCurrentOutCar(@RequestBody ReChargeVo reChargeVo) throws ParseException {
        try {
            //查询入场纪录
            List<ParkCarEnterLog> parkCarEnterLogs = chargeFeeService.getParkCarEnterLog(reChargeVo.getPlateNo(), null, reChargeVo.getParkCode());
            if (Objects.isNull(parkCarEnterLogs)) {
                return Result.error("查不到入场信息");
            }
            //得到车道信息
            ParkArmInfo parkArmInfo = parkArmInfoMapper.getParkArmBySerialNo(reChargeVo.getSerialNo());
            if (null == parkArmInfo) {
                return Result.error("查不到车道信息");
            }
            //生成订单信息保存数据库上传云端后返回前端
            Result<ParkOrderInfoVO> parkOrderInfoVOResult = sdkIdentifyResultPushLogService.getParkOrderInfoVOResult(reChargeVo);
            ParkOrderInfoVO park = parkOrderInfoVOResult.getResult();
            //选择出口相机
            park.setIpAddr(parkArmInfo.getIpAddr());
            park.setSerialNo(parkArmInfo.getSerialNo());
            //区分是否模糊匹配
            park.setVersion(JddConstant.IntNumber.INT_ONE);
            //订单信息车牌改成出场
            park.setPlateNo(reChargeVo.getOutPlateNo());
            //补录的要有个图片
            park.setOutImgPath(parkCarEnterLogs.get(0).getImgPath());
            park.setOssOutImgPath(parkCarEnterLogs.get(0).getOssImgPath());
            //如果是储值车，就直接扣费放行关弹窗
            if (isCarStored(reChargeVo, parkArmInfo, park, parkCarEnterLogs.get(0))) {
                //储值车匹配后处理
                return doParkCarStored(reChargeVo, parkCarEnterLogs.get(0), parkArmInfo, parkOrderInfoVOResult, park, JddConstant.AbnormalType.LIKE_ENTER_HASFEE);
            } else {
                //缓存的key是出场的，value是入场的
                String outPlateNo = reChargeVo.getOutPlateNo();
                String plateNo = reChargeVo.getPlateNo();
                cacheUtil.put("truePlateNo", outPlateNo, plateNo);
                //匹配后，播报钱数，扫码放行
                ledCallInterface.OutShowFeeAll(parkArmInfo.getSerialNo(), reChargeVo.getOutPlateNo(), park);
            }
            //如果出场是白名单，再次识别下就行不用处理
            parkOrderInfoVOResult.setResult(park);
            return parkOrderInfoVOResult;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("模糊匹配生成纪录异常！");
        }
    }

    /**
     * 功能描述:
     *
     * @param reChargeVo            前端发送实体
     * @param parkCarEnterLog       入场纪录
     * @param parkArmInfo           相机信息
     * @param parkOrderInfoVOResult 生成的订单信息的返回值
     * @param park                  生成的订单信息
     * @Author: lcy
     * @Date: 2021/9/29
     */
    private Result<ParkOrderInfoVO> doParkCarStored(ReChargeVo reChargeVo, ParkCarEnterLog parkCarEnterLog, ParkArmInfo parkArmInfo, Result<ParkOrderInfoVO> parkOrderInfoVOResult, ParkOrderInfoVO park, String type) {
        String plateNo = null == reChargeVo.getOutPlateNo() ? reChargeVo.getPlateNo() : reChargeVo.getOutPlateNo();
        //储值车补录与匹配都直接添加一条异常,但是状态是已支付的
        ParkCarOutAbnormalLog parkCarOutAbnormalLog = new ParkCarOutAbnormalLog();
        BeanUtils.copyProperties(parkCarEnterLog, parkCarOutAbnormalLog);
        parkCarOutAbnormalLog.setPlateNo(plateNo);
        parkCarOutAbnormalLog.setCreateTime(new Date());
        parkCarOutAbnormalLog.setCarEnterId(parkCarEnterLog.getId());
        parkCarOutAbnormalLog.setIpAddr(parkArmInfo.getIpAddr());
        parkCarOutAbnormalLog.setOrderId(park.getId());
        parkCarOutAbnormalLog.setPayStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
        parkCarOutAbnormalLog.setRemark(JddConstant.AbnormalType.ADD_ENTER_HASFEE.equals(type) ? "储值车补录入场纪录" : "储值车匹配入场纪录");
        parkCarOutAbnormalLogMapper.insert(parkCarOutAbnormalLog);
        //入场纪录设置为已出场
        parkCarEnterLogMapper.updateIsOut(plateNo);
        //储值车补录或者匹配则通过return的订单的支付状态决定是否关闭框
        park.setOrderStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
        //监控左上角显示的数据
        JSONObject successOrder = new JSONObject();
        successOrder.put("successOrder", park);
        return parkOrderInfoVOResult;
    }

    @AutoLog(value = "当相机入场识别错误，车辆出场时，自动查询可能是当前出场车辆的入场记录")
    @ApiOperation(value = "当相机入场识别错误，车辆出场时，自动查询可能是当前出场车辆的入场记录")
    @GetMapping(value = "/AutoMatchingEnterLogForCurrentOutCar")
    public Result<List<ParkCarEnterLog>> AutoMatchingEnterLogForCurrentOutCar(@RequestParam("plateNo") String plateNo) {
        Result<List<ParkCarEnterLog>> result = new Result<>();
        //将当前车牌字符串拆分成数组，并按顺序将相邻的三位数组元素组成字符串添加到集合中
        //创建集合用于模糊查询条件
        List<String> plateStrList = new ArrayList<>();
        //拆分车牌字符串，并将拆分后的元素按规则合并
        char[] plateNoChars = plateNo.toCharArray();
        //合并添加到集合中
        for (int i = 0; i < plateNoChars.length - 2; i++) {
            StringBuilder plateStr = new StringBuilder();
            plateStr.append(plateNoChars[i]);
            plateStr.append(plateNoChars[i + 1]);
            plateStr.append(plateNoChars[i + 2]);
            log.info("----------------------------------------------------------------------------" + plateStr);
            plateStrList.add(plateStr.toString());
        }
        //根据集合中的字符串进行多次数据库模糊查询
        List<ParkCarEnterLog> parkCarEnterLogLikePlateStrList = this.sdkIdentifyResultPushLogMapper.getParkCarEnterLogLikePlateStrList(plateStrList);
        //遍历查询结果，得到匹配车牌号，根据相似度算法获得与当前出场车牌的相似度
        //创建对象SimilarityRatioParkCarEnterLog集合用于保存入场记录和相似度的映射关系
        List<SimilarityRatioParkCarEnterLog> similarityRatioParkCarEnterLogs = new ArrayList<>();
        for (ParkCarEnterLog parkCarEnterLog : parkCarEnterLogLikePlateStrList) {
            String targetPlateNo = parkCarEnterLog.getPlateNo();
            //获取相似度(0-100) 结果100则为完全一样
            float similarityRatio = this.similarityRatioAlgorithm.getSimilarityRatio(plateNo, targetPlateNo);
            //相似度小于50直接抛弃该数据
            if (similarityRatio > 50.0) {
                SimilarityRatioParkCarEnterLog similarityRatioParkCarEnterLog = new SimilarityRatioParkCarEnterLog();
                BeanUtils.copyProperties(parkCarEnterLog, similarityRatioParkCarEnterLog);
                similarityRatioParkCarEnterLog.setSimilarityRatio(similarityRatio);
                similarityRatioParkCarEnterLogs.add(similarityRatioParkCarEnterLog);
            }
        }
        //根据相似度进行降序排序
        Collections.sort(similarityRatioParkCarEnterLogs, new Comparator<SimilarityRatioParkCarEnterLog>() {
            @Override
            public int compare(SimilarityRatioParkCarEnterLog o1, SimilarityRatioParkCarEnterLog o2) {
                return (int) (o2.getSimilarityRatio() - o1.getSimilarityRatio());
            }
        });
        List<SimilarityRatioParkCarEnterLog> similarityRatioParkCarEnterLogs1 = new ArrayList<>();
        if (similarityRatioParkCarEnterLogs.size() > 5) {
            similarityRatioParkCarEnterLogs1 = similarityRatioParkCarEnterLogs.subList(0, 5);
        }
        List<ParkCarEnterLog> parkCarEnterLogList = new ArrayList<>();
        for (SimilarityRatioParkCarEnterLog similarityRatioParkCarEnterLog : similarityRatioParkCarEnterLogs1) {
            ParkCarEnterLog parkCarEnterLog = new ParkCarEnterLog();
            BeanUtils.copyProperties(similarityRatioParkCarEnterLog, parkCarEnterLog);
            parkCarEnterLogList.add(parkCarEnterLog);
        }
        result.setResult(parkCarEnterLogList);
        result.setSuccess(true);
        return result;
    }

    /**
     * 当入场相机识别错误，当前车辆出场时
     * 车场管理员选中一条入场记录，此入场记录将匹配当前出场车辆，并重新执行出场逻辑
     *
     * @param parkCarEnterLogDTO
     * @return
     * @author koubolun
     */
    @AutoLog(value = "当相机入场识别错误时，为当前出场车辆匹配一条入场记录，并重新执行出场逻辑")
    @ApiOperation(value = "当相机入场识别错误时，为当前出场车辆匹配一条入场记录，并重新执行出场逻辑")
    @PostMapping(value = "/matchingEnterLogForCurrentOutCar")
    public Result matchingEnterLogForCurrentOutCar(@RequestBody ParkCarEnterLogDTO parkCarEnterLogDTO) {
        String serialNo = parkCarEnterLogDTO.getOutCameraSerialNo();
        String plateNo = parkCarEnterLogDTO.getOutCarPlateNo();
        ParkCarEnterLog parkCarEnterLog = new ParkCarEnterLog();
        BeanUtils.copyProperties(parkCarEnterLogDTO, parkCarEnterLog);
        Result<Object> result = new Result<>();
        if (StringUtils.isEmpty(serialNo)) {
            result.error500("设备序列号为空，无法匹配入场记录");
            return result;
        }
        if (ObjectUtils.isEmpty(parkCarEnterLog)) {
            result.error500("找不到该入场记录，请重试");
            return result;
        }
        //通过车牌号和设备序列号拿到最近一条相机sdk识别纪录
        SdkIdentifyResultPushLog lastTimeSdkIdentifyResultPushLogByPlate = this.sdkIdentifyResultPushLogMapper.getLastTimeSdkIdentifyResultPushLogByPlate(plateNo, serialNo);
        //通过序列号查询车辆出入口信息
        QueryWrapper<ParkArmInfo> parkArmInfoQueryWrapper = new QueryWrapper<>();
        parkArmInfoQueryWrapper.eq("serial_no", serialNo);
        ParkArmInfo parkArmInfo = this.parkArmInfoService.getOne(parkArmInfoQueryWrapper);
        //为当前车辆匹配入场信息
        parkCarEnterLog.setPlateNo(plateNo);
        parkCarEnterLog.setId(null);
        this.parkCarEnterLogService.save(parkCarEnterLog);
        //缓存当前车牌
        String ossImgPath = lastTimeSdkIdentifyResultPushLogByPlate.getOssImg();
        String localImgPath = lastTimeSdkIdentifyResultPushLogByPlate.getImg();
        String armName = parkArmInfo.getArmName();
        cacheUtil.put(CacheConstant.CURRENT_EXIT_LICENSE_PLATE, serialNo, plateNo + "#" + ossImgPath + "#" + localImgPath + "#" + armName);
        log.info("重新匹配入场信息的出口缓存:SerialNo:{}>>>>>>>>>plateNo:{}", serialNo, plateNo);
        //根据sdk识别结果再次调用出场逻辑
        try {
            this.sdkIdentifyResultPushLogV3Service.identifyJudge(lastTimeSdkIdentifyResultPushLogByPlate, parkArmInfo);
            result.setSuccess(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("出场失败");
        }
        return result;
    }


    /**
     * 分页列表查询
     *
     * @param sdkIdentifyResultPushLog
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-分页列表查询")
    @ApiOperation(value = "sdk识别结果管理-分页列表查询", notes = "sdk识别结果管理-分页列表查询")
    @GetMapping(value = "/list")
    public Result<IPage<SdkIdentifyResultPushLog>> queryPageList(SdkIdentifyResultPushLog sdkIdentifyResultPushLog,
                                                                 @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                                 @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                                 HttpServletRequest req) {
        Result<IPage<SdkIdentifyResultPushLog>> result = new Result<IPage<SdkIdentifyResultPushLog>>();
        QueryWrapper<SdkIdentifyResultPushLog> queryWrapper = QueryGenerator.initQueryWrapper(sdkIdentifyResultPushLog, req.getParameterMap());
        Page<SdkIdentifyResultPushLog> page = new Page<SdkIdentifyResultPushLog>(pageNo, pageSize);
        IPage<SdkIdentifyResultPushLog> pageList = sdkIdentifyResultPushLogService.page(page, queryWrapper);

        result.setSuccess(true);
        result.setResult(pageList);
        return result;
    }

    @AutoLog(value = "sdk软触发")
    @ApiOperation(value = "sdk软触发", notes = "sdk软触发")
    @GetMapping(value = "/triggerExt")
    public Result<?> triggerExt(@RequestParam("serialNo") String serialNo) {
        return sdkIdentifyResultPushLogService.triggerExt(serialNo);
    }

    /**
     * 添加
     *
     * @param sdkIdentifyResultPushLog
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-添加")
    @ApiOperation(value = "sdk识别结果管理-添加", notes = "sdk识别结果管理-添加")
    @PostMapping(value = "/add")
    public Result<SdkIdentifyResultPushLog> add(@RequestBody SdkIdentifyResultPushLog sdkIdentifyResultPushLog) {
        Result<SdkIdentifyResultPushLog> result = new Result<SdkIdentifyResultPushLog>();
        try {
            sdkIdentifyResultPushLogService.save(sdkIdentifyResultPushLog);
            result.success("添加成功！");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
        }
        return result;
    }

    /**
     * 编辑
     *
     * @param sdkIdentifyResultPushLog
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-编辑")
    @ApiOperation(value = "sdk识别结果管理-编辑", notes = "sdk识别结果管理-编辑")
    @PutMapping(value = "/edit")
    public Result<SdkIdentifyResultPushLog> edit(@RequestBody SdkIdentifyResultPushLog sdkIdentifyResultPushLog) {
        Result<SdkIdentifyResultPushLog> result = new Result<SdkIdentifyResultPushLog>();
        SdkIdentifyResultPushLog sdkIdentifyResultPushLogEntity = sdkIdentifyResultPushLogService.getById(sdkIdentifyResultPushLog.getId());
        if (sdkIdentifyResultPushLogEntity == null) {
            result.error500("未找到对应实体");
        } else {
            boolean ok = sdkIdentifyResultPushLogService.updateById(sdkIdentifyResultPushLog);
            //TODO 返回false说明什么？
            if (ok) {
                result.success("修改成功!");
            }
        }

        return result;
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-通过id删除")
    @ApiOperation(value = "sdk识别结果管理-通过id删除", notes = "sdk识别结果管理-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        try {
            sdkIdentifyResultPushLogService.removeById(id);
        } catch (Exception e) {
            log.error("删除失败", e.getMessage());
            return Result.error("删除失败!");
        }
        return Result.ok("删除成功!");
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-批量删除")
    @ApiOperation(value = "sdk识别结果管理-批量删除", notes = "sdk识别结果管理-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<SdkIdentifyResultPushLog> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        Result<SdkIdentifyResultPushLog> result = new Result<SdkIdentifyResultPushLog>();
        if (ids == null || "".equals(ids.trim())) {
            result.error500("参数不识别！");
        } else {
            this.sdkIdentifyResultPushLogService.removeByIds(Arrays.asList(ids.split(",")));
            result.success("删除成功!");
        }
        return result;
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @AutoLog(value = "sdk识别结果管理-通过id查询")
    @ApiOperation(value = "sdk识别结果管理-通过id查询", notes = "sdk识别结果管理-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<SdkIdentifyResultPushLog> queryById(@RequestParam(name = "id", required = true) String id) {
        Result<SdkIdentifyResultPushLog> result = new Result<SdkIdentifyResultPushLog>();
        SdkIdentifyResultPushLog sdkIdentifyResultPushLog = sdkIdentifyResultPushLogService.getById(id);
        if (sdkIdentifyResultPushLog == null) {
            result.error500("未找到对应实体");
        } else {
            result.setResult(sdkIdentifyResultPushLog);
            result.setSuccess(true);
        }
        return result;
    }

    /**
     * 导出excel
     *
     * @param request
     * @param response
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response, SdkIdentifyResultPushLog sdkIdentifyResultPushLog) {
        // Step.1 组装查询条件
        QueryWrapper<SdkIdentifyResultPushLog> queryWrapper = QueryGenerator.initQueryWrapper(sdkIdentifyResultPushLog, request.getParameterMap());

        //Step.2 AutoPoi 导出Excel
        ModelAndView mv = new ModelAndView(new EasypoiSingleExcelView());
        List<SdkIdentifyResultPushLog> pageList = sdkIdentifyResultPushLogService.list(queryWrapper);
        //导出文件名称
        mv.addObject(NormalExcelConstants.FILE_NAME, "sdk识别结果管理列表");
        mv.addObject(NormalExcelConstants.CLASS, SdkIdentifyResultPushLog.class);
        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("sdk识别结果管理列表数据", "导出信息"));
        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
        return mv;
    }

    /**
     * 通过excel导入数据
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取上传文件对象
            MultipartFile file = entity.getValue();
            ImportParams params = ImportParams.builder().build();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<SdkIdentifyResultPushLog> listSdkIdentifyResultPushLogs = ExcelImportUtil.importExcel(file.getInputStream(), SdkIdentifyResultPushLog.class, params);
                sdkIdentifyResultPushLogService.saveBatch(listSdkIdentifyResultPushLogs);
                return Result.ok("文件导入成功！数据行数:" + listSdkIdentifyResultPushLogs.size());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败:" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.ok("文件导入失败！");
    }

    @ApiOperation(value = "测试出入场逻辑", notes = "测试出入场逻辑")
    @RequestMapping("/test")
    public Result<?> testIdentify(String plateNo, String serialNo, Integer carType) {
        ParkArmInfo parkArmInfo = parkArmInfoMapper.getParkArmBySerialNo(serialNo);
        if (null == parkArmInfo) {
            return Result.error("车道信息不存在");
        }

        SdkIdentifyResultPushLog sdkIdentifyResultPushLog = new SdkIdentifyResultPushLog();
        sdkIdentifyResultPushLog.setLicense(plateNo);
        sdkIdentifyResultPushLog.setParkName(parkArmInfo.getParkName());
        sdkIdentifyResultPushLog.setParkCode(parkArmInfo.getParkCode());
        sdkIdentifyResultPushLog.setNType(carType);
        sdkIdentifyResultPushLog.setSerialNo(serialNo);
        sdkIdentifyResultPushLogService.save(sdkIdentifyResultPushLog);
        try {
            sdkIdentifyResultPushLogV3Service.identifyJudge(sdkIdentifyResultPushLog, parkArmInfo);
        } catch (Exception e) {
            log.error(e.getMessage());
            return Result.error(e.getMessage());
        }
        return Result.ok();
    }

    @ApiOperation(value = "测试出入场逻辑", notes = "测试出入场逻辑")
    @RequestMapping("/testMonthly")
    public Result<?> testIdentify(String serialNo) {
        ParkArmInfo parkArmInfo = parkArmInfoMapper.getParkArmBySerialNo(serialNo);
        if (null == parkArmInfo) {
            return Result.error("车道信息不存在");
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", "0");
        List<ParkCarMonthly> list = parkCarMonthlyService.list(queryWrapper);
        list.stream().forEach(item -> {
            SdkIdentifyResultPushLog resultPushLog = new SdkIdentifyResultPushLog();
            String plateNo = item.getPlateNo();
            resultPushLog.setLicense(plateNo);
            resultPushLog.setParkName(parkArmInfo.getParkName());
            resultPushLog.setParkCode(parkArmInfo.getParkCode());
            resultPushLog.setNType(1);
            resultPushLog.setSerialNo(serialNo);
            sdkIdentifyResultPushLogService.save(resultPushLog);
            try {
                sdkIdentifyResultPushLogV3Service.identifyJudge(resultPushLog, parkArmInfo);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return;
        });

        return Result.ok();
    }

    @ApiOperation(value = "测试LED显示二维码", notes = "测试LED显示二维码")
    @GetMapping("/testLEDForQRCode")
    public Result<?> testLEDForQRCode(String serialNo) {

        String handle = cacheUtill.get(CacheConstant.SERIAL_HANDLE, serialNo);
        if (org.apache.commons.lang.StringUtils.isBlank(handle)) {
            return Result.error("请对设备进行初始化");
        }
        String imageStr;
        byte[] data = null;
        try {
            imageStr = decodeQRCodeImage("C:/Users/jddhlw966/project-need/baidu.png");
            data = LedControlUtils.showQRCodeOrder(imageStr);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //开启透明通道
        int i = Integer.parseInt(handle);
        int ret = cameraSdk.zhenshiSdk.VzLPRClient_SerialSend(i, data, data.length);
        if (ret != 0) {
            return Result.error("播放失败!");
        }
        return null;
    }

    /**
     * 获取二维码图片的内容
     *
     * @param filepath --->文件路径
     * @return
     */
    public static String decodeQRCodeImage(String filepath){
        com.google.zxing.Result result = null;
        try {
            BufferedImage image= ImageIO.read(new File(filepath));
            BinaryBitmap bb=new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
            HashMap map =new HashMap();
            map.put(DecodeHintType.CHARACTER_SET, "utf-8");
            result = new MultiFormatReader().decode(bb,map);
        } catch (Exception e) {
            log.error("解析获取二维码内容异常");
        }
        if (Objects.isNull(result)){
            log.error("解析获取二维码内容为空");
            return null;
        }else {
            return result.toString();
        }
    }

    /**
     * 根据车辆编号、车牌类型匹配停车场的车辆类型Id
     *
     * @param type 车牌类型
     * @return java.lang.String
     * @version 1.0
     */
    private String getCarType(int type) {
        String result = null;
        List<ConfigCarType> list = carTypeService.getCarTypeList();
        for (ConfigCarType carType : list) {
            String cardTypeId = carType.getId();
            List<String> typeNo = Arrays.asList(carType.getCarTypeNo().split(","));
            if (typeNo.contains(type + "")) {
                result = cardTypeId;
                return result;
            }
        }
        return result;
    }

    /**
     * @description: 根据入场记录查询订单信息，查询支付总金额
     * @param: [carEnterLogId]
     * @return: java.util.Map
     * @author liujunwei@jdd966.com
     * @date: 2021/4/26 15:22
     */

    private Map getOrderInfo(String carEnterLogId) {
        Map map = new HashMap(3);
        //根据最近的入场记录id查询对应的支付订单
        QueryWrapper<ParkOrderInfo> orderWrapper = new QueryWrapper<>();
        orderWrapper.eq("park_log_id", carEnterLogId);
        orderWrapper.eq("order_status", "2");
        orderWrapper.orderByDesc("create_time");
        List<ParkOrderInfo> orderInfos = parkOrderInfoService.list(orderWrapper);
        // 已支付订单总费用
        int orderTotalFee = 0;
        for (ParkOrderInfo orderInfo : orderInfos) {
            int fee = getIntegerFromString(orderInfo.getChargePaid()) + getIntegerFromString(orderInfo.getTotalDiscAmt()) + getIntegerFromString(orderInfo.getCouponAmt());
            orderTotalFee = orderTotalFee + fee;
        }
        map.put("orderInfoList", orderInfos);
        map.put("paidFee", orderTotalFee);
        return map;
    }

    private int getIntegerFromString(String str) {
        if (StringUtils.isBlank(str)) {
            return 0;
        }
        return Integer.parseInt(str);
    }

    /**
     * 发送请求云端同步月租车位状态
     *
     * @param restTemplateSpaceVo
     * @return com.jdd.common.api.vo.ResultVo
     * @author jdd孙庆伟
     * @date 2021/10/15 14:15:05
     * @version 1.0
     */
    public ResultVo sendCloudSynSpace(RestTemplateSpaceVo restTemplateSpaceVo) {
        String url = "";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //封装参数
        MultiValueMap<String, String> stringStringSortedMap = EncapsulationSignDataUtils.encapsulationParameters(restTemplateSpaceVo, appId, appScrect);
        // 组装请求体
        HttpEntity<MultiValueMap<String, String>> request =
                new HttpEntity<MultiValueMap<String, String>>(stringStringSortedMap, headers);
        ResponseEntity<ResultVo> cmsResultDTO = restTemplateUtils.post(url, request, ResultVo.class);
        return cmsResultDTO.getBody();
    }

    private Boolean freeIf(String type) {
        List<String> list = CarType.getFreeEnum();
        return list.contains(type);
    }

    @Scheduled(cron = "0/30 * * * * ?")
    private void entranceLedShow() throws Exception {
        ConfigParkInfo configParkInfo = configParkInfoService.findConfigParkInfoByParkCode();
        ParkCarEnterLog lastParkCarEnterLog = parkCarEnterLogService.getLastCarEnterLogNoPlateNo(parkCode, "0");
        if (null == lastParkCarEnterLog) {
            return;
        }
        Date carEnterTime = lastParkCarEnterLog.getCreateTime();
        Date date = new Date();
        long daysDverdue = cn.hutool.core.date.DateUtil.between(date, carEnterTime, DateUnit.SECOND);
        if (daysDverdue > 60) {
            QueryWrapper<ParkArmInfo> wrapper = new QueryWrapper<>();
            wrapper.isNotNull("target_area_id").ne("target_area_id", "");
            List<ParkArmInfo> list = parkArmInfoService.list(wrapper);
            Integer carNumber = getSurplusCarNumber(configParkInfo);
            String formatDate = DateUtil.formatDate(date, "yyyy-MM-dd");
            if (JddConstant.CameraControl.CONTROLPANEL_FANGKONG.equals(configParkInfo.getControlPanelType())) {
                for (ParkArmInfo parkArmInfo : list) {
                    sdkCallInterface.Sdk485LedAdvertising(parkArmInfo.getSerialNo(), "车位:" + (carNumber < 0 ? 0 : carNumber), "04000100");
                    // 取消临显内容
//                sdkCallInterface.Sdk485LedNoContentCommunication(parkArmInfo.getSerialNo());
//                    sdkCallInterface.Sdk485LedAdvertising(parkArmInfo.getSerialNo(),formatDate,"02000100");
                }
            }
            if (JddConstant.CameraControl.CONTROLPANEL_FEILIDE.equals(configParkInfo.getControlPanelType())) {
                for (ParkArmInfo parkArmInfo : list) {
                    sdkCallInterface.Sdk485TestContentCommunication(parkArmInfo.getSerialNo(), "车位:" + (carNumber < 0 ? 0 : carNumber), LedConstant.feilideLongFourLineOne);
                    sdkCallInterface.Sdk485LedAdvertising(parkArmInfo.getSerialNo(), "车位:" + (carNumber < 0 ? 0 : carNumber), LedConstant.feilideTextFourLineOne);
                }
            }
            if (JddConstant.CameraControl.CONTROLPANEL_SMALL_FANGKONG.equals(configParkInfo.getControlPanelType())) {
                for (ParkArmInfo parkArmInfo : list) {
                    sdkCallInterface.Sdk485LedAdvertising(parkArmInfo.getSerialNo(), "车位:" + (carNumber < 0 ? 0 : carNumber), "01000200");
                }
            }
        }
    }

    private void exitLedShow() throws Exception {
        ParkCarOutLog lastParkOutEnterLog = parkCarOutLogService.getLastParkOutEnterLog(parkCode);
        if (ObjectUtil.isEmpty(lastParkOutEnterLog)) {
            return;
        }
        Date carEnterTime = lastParkOutEnterLog.getCreateTime();
        Date date = new Date();
        long daysDverdue = cn.hutool.core.date.DateUtil.between(date, carEnterTime, DateUnit.SECOND);
        if (daysDverdue > 30) {
            QueryWrapper<ParkArmInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("park_code", parkCode);
            wrapper.eq("arm_status", "1");
            wrapper.isNull("target_area_id").ne("target_area_id", "");
            List<ParkArmInfo> list = parkArmInfoService.list(wrapper);
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            String formatDate = DateUtil.formatDate(date, "yyyy-MM-dd");
            for (ParkArmInfo parkArmInfo : list) {
                // 第三行显示日期
                sdkCallInterface.Sdk485TestContentCommunicationAll(parkArmInfo.getSerialNo(), formatDate, "03000100");
            }
        }
    }

    public Integer getSurplusCarNumber(ConfigParkInfo configParkInfo) {
        //车场临时车位数
        Integer temporaryParking = configParkInfo.getTemporaryParking();
        Integer noOutCarNumber = parkCarEnterLogMapper.getNoOutCarNumber();
        return temporaryParking - noOutCarNumber;
    }
}
